#ifndef LW_QUEUE_H
#define LW_QUEUE_H

#include <queue>

#include "abstract/EdgeAccessList.h"

template<typename T>
class Queue : public EdgeAccessList<T> {
protected:

    std::queue<T> wrappedList;
	static const std::string emptyAccessMessage;

public:

	Queue() {
		
	}

    virtual ~Queue() {
    }

    /**
     * Retrieves and removes the first element from this queue.
     */
    virtual inline Queue& operator>>(T& e) {
        Pop(e);
        return *this;
    }

    /**
     * Adds the specified element to the end of this queue.
     */
    virtual inline void Push(const T& e) {
        wrappedList.push(e);
    }

    /**
     * Returns the first element in this queue.
     */
    virtual inline T& First() {
		if(!Empty()) {
			return wrappedList.front();
		}

		throw std::runtime_error(emptyAccessMessage);
    }

    /**
     * Returns the first element in this queue.
     */
    virtual inline const T& First() const {
		if(!Empty()) {
			return wrappedList.front();
		}

		throw std::runtime_error(emptyAccessMessage);
    }

    /**
     * Returns the last element in this queue.
     */
    virtual inline T& Last() {
		if(!Empty()) {
			return wrappedList.back();
		}

		throw std::runtime_error(emptyAccessMessage);
    }

    /**
     * Returns the last element in this queue.
     */
    virtual inline const T& Last() const {
		if(!Empty()) {
			return wrappedList.back();
		}

		throw std::runtime_error(emptyAccessMessage);
    }

    /**
     * Removes the first element from this queue.
     */
    virtual inline void Pop() {
		if(!Empty()) {
			wrappedList.pop();
			return;
		}

		throw std::runtime_error(emptyAccessMessage);
    }

    /**
     * Retrieves and removes the first element from this queue.
     */
    virtual inline void Pop(T& e) {
		if(!Empty()) {
			e = wrappedList.front();
			wrappedList.pop();
			return;
		}

		throw std::runtime_error(emptyAccessMessage);
    }

    /**
     * Returns the number of elements in this queue.
     */
    virtual inline int Size() const {
        return wrappedList.size();
    }

    /**
     * Returns true if this queue has no elements.
     */
    virtual inline bool Empty() const {
        return wrappedList.empty();
    }

    /**
     * Clears the queue by removing each element in a loop.
     */
    virtual void Clear() {
		if(!Empty()) {
			wrappedList.pop();
		}
    }
};

template<typename T>
const std::string Queue<T>::emptyAccessMessage =  "Queue (std::queue) is empty";

#endif //LW_QUEUE_H
